let snd_of_fst_table list = (
	let table = Hashtbl.create (List.length list) in
	List.iter (fun (s, w) -> Hashtbl.add table s w) list;
	table
);;

let fst_of_snd_table list = (
	let table = Hashtbl.create (List.length list) in
	List.iter (fun (s, w) -> Hashtbl.add table w s) list;
	table
);;

module Reserved = struct

	type ada_reserved_word = 
		| ABORT
		| ABS
		| ABSTRACT
		| ACCEPT
		| ACCESS
		| ALIASED
		| ALL
		| AND
		| ARRAY
		| AT
		| BEGIN
		| BODY
		| CASE
		| CONSTANT
		| DECLARE
		| DELAY
		| DELTA
		| DIGITS
		| DO
		| ELSE
		| ELSIF
		| END
		| ENTRY
		| EXCEPTION
		| EXIT
		| FOR
		| FUNCTION
		| GENERIC
		| GOTO
		| IF
		| IN
		| INTERFACE
		| IS
		| LIMITED
		| LOOP
		| MOD
		| NEW
		| NOT
		| NULL
		| OF
		| OR
		| OTHERS
		| OUT
		| OVERRIDING
		| PACKAGE
		| PRAGMA
		| PRIVATE
		| PROCEDURE
		| PROTECTED
		| RAISE
		| RANGE
		| RECORD
		| REM
		| RENAMES
		| REQUEUE
		| RETURN  
		| REVERSE  
		| SELECT  
		| SEPARATE  
		| SUBTYPE  
		| SYNCHRONIZED  
		| TAGGED  
		| TASK  
		| TERMINATE  
		| THEN  
		| TYPE  
		| UNTIL  
		| USE  
		| WHEN  
		| WHILE  
		| WITH  
		| XOR;;

	let reserved_word_table = [
		("ABORT", ABORT);
		("ABS", ABS);
		("ABSTRACT", ABSTRACT);
		("ACCEPT", ACCEPT);
		("ACCESS", ACCESS);
		("ALIASED", ALIASED);
		("ALL", ALL);
		("AND", AND);
		("ARRAY", ARRAY);
		("AT", AT);
		("BEGIN", BEGIN);
		("BODY", BODY);
		("CASE", CASE);
		("CONSTANT", CONSTANT);
		("DECLARE", DECLARE);
		("DELAY", DELAY);
		("DELTA", DELTA);
		("DIGITS", DIGITS);
		("DO", DO);
		("ELSE", ELSE);
		("ELSIF", ELSIF);
		("END", END);
		("ENTRY", ENTRY);
		("EXCEPTION", EXCEPTION);
		("EXIT", EXIT);
		("FOR", FOR);
		("FUNCTION", FUNCTION);
		("GENERIC", GENERIC);
		("GOTO", GOTO);
		("IF", IF);
		("IN", IN);
		("INTERFACE", INTERFACE);
		("IS", IS);
		("LIMITED", LIMITED);
		("LOOP", LOOP);
		("MOD", MOD);
		("NEW", NEW);
		("NOT", NOT);
		("NULL", NULL);
		("OF", OF);
		("OR", OR);
		("OTHERS", OTHERS);
		("OUT", OUT);
		("OVERRIDING", OVERRIDING);
		("PACKAGE", PACKAGE);
		("PRAGMA", PRAGMA);
		("PRIVATE", PRIVATE);
		("PROCEDURE", PROCEDURE);
		("PROTECTED", PROTECTED);
		("RAISE", RAISE);
		("RANGE", RANGE);
		("RECORD", RECORD);
		("REM", REM);
		("RENAMES", RENAMES);
		("REQUEUE", REQUEUE);
		("RETURN", RETURN);
		("REVERSE", REVERSE);
		("SELECT", SELECT);
		("SEPARATE", SEPARATE);
		("SUBTYPE", SUBTYPE);
		("SYNCHRONIZED", SYNCHRONIZED);
		("TAGGED", TAGGED);
		("TASK", TASK);
		("TERMINATE", TERMINATE);
		("THEN", THEN);
		("TYPE", TYPE);
		("UNTIL", UNTIL);
		("USE", USE);
		("WHEN", WHEN);
		("WHILE", WHILE);
		("WITH", WITH);
		("XOR", XOR)
	];;

end;;

let rw_of_string_table = snd_of_fst_table Reserved.reserved_word_table;;
let string_of_rw_table = fst_of_snd_table Reserved.reserved_word_table;;

let is_rw (s: string): bool = (
	Hashtbl.mem rw_of_string_table s
);;

let rw_of_string (s: string): Reserved.ada_reserved_word = (
	Hashtbl.find rw_of_string_table s
);;

let string_of_rw (k: Reserved.ada_reserved_word): string = (
	Hashtbl.find string_of_rw_table k
);;

module Attribute = struct

	type ada_attribute = 
		| Unknown of string
		| Access
		| Address
		| Adjacent
		| Aft
		| Alignment
		| Base
		| Bit_Order
		| Body_Version
		| Callable
		| Caller
		| Ceiling
		| Class
		| Component_Size
		| Compose
		| Constrained
		| Copy_Sign
		| Count
		| Definite
		| Delta
		| Denorm
		| Digits
		| Exponent
		| External_Tag
		| First
		| First_Bit
		| Floor
		| Fore
		| Fraction
		| Identity
		| Image
		| Input
		| Last
		| Last_Bit
		| Leading_Part
		| Length
		| Machine
		| Machine_Emax
		| Machine_Emin
		| Machine_Mantissa
		| Machine_Overflows
		| Machine_Radix
		| Machine_Rounding
		| Machine_Rounds
		| Max
		| Max_Size_In_Storage_Elements
		| Min
		| Mod
		| Model
		| Model_Emin
		| Model_Epsilon
		| Model_Mantissa
		| Model_Small
		| Modulus
		| Output
		| Partition_Id
		| Pos
		| Position
		| Pred
		| Range
		| Read
		| Remainder
		| Round
		| Rounding
		| Safe_First
		| Safe_Last
		| Scale
		| Scaling
		| Signed_Zeros
		| Size
		| Small
		| Storage_Pool
		| Storage_Size
		| Stream_Size
		| Succ
		| Tag
		| Terminated
		| Truncation
		| Unbiased_Rounding
		| Unchecked_Access
		| Val
		| Valid
		| Value
		| Version
		| Wide_Image
		| Wide_Value
		| Wide_Wide_Image
		| Wide_Wide_Value
		| Wide_Wide_Width
		| Wide_Width
		| Width
		| Write;;

	let attribute_table = [
		("ACCESS", Access);
		("ADDRESS", Address);
		("ADJACENT", Adjacent);
		("AFT", Aft);
		("ALIGNMENT", Alignment);
		("BASE", Base);
		("BIT_ORDER", Bit_Order);
		("BODY_VERSION", Body_Version);
		("CALLABLE", Callable);
		("CALLER", Caller);
		("CEILING", Ceiling);
		("CLASS", Class);
		("COMPONENT_SIZE", Component_Size);
		("COMPOSE", Compose);
		("CONSTRAINED", Constrained);
		("COPY_SIGN", Copy_Sign);
		("COUNT", Count);
		("DEFINITE", Definite);
		("DELTA", Delta);
		("DENORM", Denorm);
		("DIGITS", Digits);
		("EXPONENT", Exponent);
		("EXTERNAL_TAG", External_Tag);
		("FIRST", First);
		("FIRST_BIT", First_Bit);
		("FLOOR", Floor);
		("FORE", Fore);
		("FRACTION", Fraction);
		("IDENTITY", Identity);
		("IMAGE", Image);
		("INPUT", Input);
		("LAST", Last);
		("LAST_BIT", Last_Bit);
		("LEADING_PART", Leading_Part);
		("LENGTH", Length);
		("MACHINE", Machine);
		("MACHINE_EMAX", Machine_Emax);
		("MACHINE_EMIN", Machine_Emin);
		("MACHINE_MANTISSA", Machine_Mantissa);
		("MACHINE_OVERFLOWS", Machine_Overflows);
		("MACHINE_RADIX", Machine_Radix);
		("MACHINE_ROUNDING", Machine_Rounding);
		("MACHINE_ROUNDS", Machine_Rounds);
		("MAX", Max);
		("MAX_SIZE_IN_STORAGE_ELEMENTS", Max_Size_In_Storage_Elements);
		("MIN", Min);
		("MOD", Mod);
		("MODEL", Model);
		("MODEL_EMIN", Model_Emin);
		("MODEL_EPSILON", Model_Epsilon);
		("MODEL_MANTISSA", Model_Mantissa);
		("MODEL_SMALL", Model_Small);
		("MODULUS", Modulus);
		("OUTPUT", Output);
		("PARTITION_ID", Partition_Id);
		("POS", Pos);
		("POSITION", Position);
		("PRED", Pred);
		("RANGE", Range);
		("READ", Read);
		("REMAINDER", Remainder);
		("ROUND", Round);
		("ROUNDING", Rounding);
		("SAFE_FIRST", Safe_First);
		("SAFE_LAST", Safe_Last);
		("SCALE", Scale);
		("SCALING", Scaling);
		("SIGNED_ZEROS", Signed_Zeros);
		("SIZE", Size);
		("SMALL", Small);
		("STORAGE_POOL", Storage_Pool);
		("STORAGE_SIZE", Storage_Size);
		("STREAM_SIZE", Stream_Size);
		("SUCC", Succ);
		("TAG", Tag);
		("TERMINATED", Terminated);
		("TRUNCATION", Truncation);
		("UNBIASED_ROUNDING", Unbiased_Rounding);
		("UNCHECKED_ACCESS", Unchecked_Access);
		("VAL", Val);
		("VALID", Valid);
		("VALUE", Value);
		("VERSION", Version);
		("WIDE_IMAGE", Wide_Image);
		("WIDE_VALUE", Wide_Value);
		("WIDE_WIDE_IMAGE", Wide_Wide_Image);
		("WIDE_WIDE_VALUE", Wide_Wide_Value);
		("WIDE_WIDE_WIDTH", Wide_Wide_Width);
		("WIDE_WIDTH", Wide_Width);
		("WIDTH", Width);
		("WRITE", Write)
	];;

end;;

let attr_of_string_table = snd_of_fst_table Attribute.attribute_table;;
let string_of_attr_table = fst_of_snd_table Attribute.attribute_table;;

let is_attr (s: string): bool = (
	Hashtbl.mem attr_of_string_table s
);;

let attr_of_string (s: string): Attribute.ada_attribute = (
	Hashtbl.find attr_of_string_table s
);;

let string_of_attr (k: Attribute.ada_attribute): string = (
	Hashtbl.find string_of_attr_table k
);;

module Pragma = struct

	type ada_pragma = 
		| Unknown of string
		| All_Calls_Remote
		| Assert
		| Assertion_Policy
		| Asynchronous
		| Atomic
		| Atomic_Components
		| Attach_Handler
		| Controlled
		| Convention
		| Detect_Blocking
		| Discard_Names
		| Elaborate
		| Elaborate_All
		| Elaborate_Body
		| Export
		| Import
		| Inline
		| Inspection_Point
		| Interrupt_Handler
		| Interrupt_Priority
		| Linker_Options
		| List
		| Locking_Policy
		| No_Return
		| Normalize_Scalars
		| Optimize
		| Pack
		| Page
		| Partition_Elaboration_Policy
		| Preelaborable_Initialization
		| Preelaborate
		| Priority
		| Priority_Specific_Dispatching
		| Profile
		| Pure
		| Queuing_Policy
		| Relative_Deadline
		| Remote_Call_Interface
		| Remote_Types
		| Restrictions
		| Reviewable
		| Shared_Passive
		| Storage_Size
		| Suppress
		| Task_Dispatching_Policy
		| Unchecked_Union
		| Unsuppress
		| Volatile
		| Volatile_Components;;

	let pragma_table = [
		("ALL_CALLS_REMOTE", All_Calls_Remote);
		("ASSERT", Assert);
		("ASSERTION_POLICY", Assertion_Policy);
		("ASYNCHRONOUS", Asynchronous);
		("ATOMIC", Atomic);
		("ATOMIC_COMPONENTS", Atomic_Components);
		("ATTACH_HANDLER", Attach_Handler);
		("CONTROLLED", Controlled);
		("CONVENTION", Convention);
		("DETECT_BLOCKING", Detect_Blocking);
		("DISCARD_NAMES", Discard_Names);
		("ELABORATE", Elaborate);
		("ELABORATE_ALL", Elaborate_All);
		("ELABORATE_BODY", Elaborate_Body);
		("EXPORT", Export);
		("IMPORT", Import);
		("INLINE", Inline);
		("INSPECTION_POINT", Inspection_Point);
		("INTERRUPT_HANDLER", Interrupt_Handler);
		("INTERRUPT_PRIORITY", Interrupt_Priority);
		("LINKER_OPTIONS", Linker_Options);
		("LIST", List);
		("LOCKING_POLICY", Locking_Policy);
		("NO_RETURN", No_Return);
		("NORMALIZE_SCALARS", Normalize_Scalars);
		("OPTIMIZE", Optimize);
		("PACK", Pack);
		("PAGE", Page);
		("PARTITION_ELABORATION_POLICY", Partition_Elaboration_Policy);
		("PREELABORABLE_INITIALIZATION", Preelaborable_Initialization);
		("PREELABORATE", Preelaborate);
		("PRIORITY", Priority);
		("PRIORITY_SPECIFIC_DISPATCHING", Priority_Specific_Dispatching);
		("PROFILE", Profile);
		("PURE", Pure);
		("QUEUING_POLICY", Queuing_Policy);
		("RELATIVE_DEADLINE", Relative_Deadline);
		("REMOTE_CALL_INTERFACE", Remote_Call_Interface);
		("REMOTE_TYPES", Remote_Types);
		("RESTRICTIONS", Restrictions);
		("REVIEWABLE", Reviewable);
		("SHARED_PASSIVE", Shared_Passive);
		("STORAGE_SIZE", Storage_Size);
		("SUPPRESS", Suppress);
		("TASK_DISPATCHING_POLICY", Task_Dispatching_Policy);
		("UNCHECKED_UNION", Unchecked_Union);
		("UNSUPPRESS", Unsuppress);
		("VOLATILE", Volatile);
		("VOLATILE_COMPONENTS", Volatile_Components)
	];;

end;;

let pragma_of_string_table = snd_of_fst_table Pragma.pragma_table;;
let string_of_pragma_table = fst_of_snd_table Pragma.pragma_table;;

let is_pragma (s: string): bool = (
	Hashtbl.mem pragma_of_string_table s
);;

let pragma_of_string (s: string): Pragma.ada_pragma = (
	Hashtbl.find pragma_of_string_table s
);;

let string_of_pragma (k: Pragma.ada_pragma): string = (
	Hashtbl.find string_of_pragma_table k
);;

module Identifier = struct
	let uppercase (s: string): string = (
		let r = String.copy s in
		for i = 0 to String.length s - 1 do
			let c = r.[i] in
			if c >= 'a' && c <= 'z' then r.[i] <- char_of_int (int_of_char c - 32)
		done;
		r
	);;
end;;

module type NumericType = sig
	type t;;
	val zero: t;;
	val scaling: base: int -> adjustment: int -> t -> t;;
	val of_basedstring: base: int -> string -> t;;
	val pp: quali: bool -> paren: bool -> Format.formatter -> t -> unit;;
end;;

module type LexicalElementType = sig
	type integer;;
	type real;;
	type t =
		| R of Reserved.ada_reserved_word
		| A of Attribute.ada_attribute
		| P of Pragma.ada_pragma
		| I of string * string
		| Integer_literal of integer
		| Real_literal of real
		| Character_literal of string
		| Character_code of int * int32 (* bit-width, unicode *)
		| String_literal of string
		| Invalid_literal
		| LT
		| LE
		| GT
		| GE
		| EQ
		| NE
		| L_label (* << *)
		| R_label (* >> *)
		| Box (* <> *)
		| Arrow (* >= *)
		| Slash
		| Semicolon
		| Colon
		| Assign (* := *)
		| Asterisk
		| Exponentiate (* ** *)
		| Comma
		| Period
		| D_dot (* .. *)
		| Ampersand
		| Plus
		| Minus
		| Quote
		| L_paren
		| R_paren
		| Vertical
		| Lexical_error of string
		| Eof;;
	val eof: t;;
	val invalid: t option;;
	val compare: t -> t -> int;;
	val pp_pattern: quali: bool -> paren: bool -> Format.formatter -> t -> unit
	val pp: quali: bool -> paren: bool -> Format.formatter -> t -> unit
	val pp_typename: quali: bool -> paren: bool -> Format.formatter -> t list -> unit
end;;

module type Modules = sig
	val element_module: string;;
	val reserved_module: string;;
	val pragma_module: string;;
	val attribute_module: string;;
end;;

module Element (Integer: NumericType) (Real: NumericType)
	(Modules: Modules): (LexicalElementType with type integer = Integer.t and type real = Real.t) =
struct
	
	type integer = Integer.t;;
	type real = Real.t;;
	
	type t =
		| R of Reserved.ada_reserved_word
		| A of Attribute.ada_attribute
		| P of Pragma.ada_pragma
		| I of string * string
		| Integer_literal of integer
		| Real_literal of real
		| Character_literal of string
		| Character_code of int * int32 (* bit-width, unicode *)
		| String_literal of string
		| Invalid_literal
		| LT
		| LE
		| GT
		| GE
		| EQ
		| NE
		| L_label (* << *)
		| R_label (* >> *)
		| Box (* <> *)
		| Arrow (* >= *)
		| Slash
		| Semicolon
		| Colon
		| Assign (* := *)
		| Asterisk
		| Exponentiate (* ** *)
		| Comma
		| Period
		| D_dot (* .. *)
		| Ampersand
		| Plus
		| Minus
		| Quote
		| L_paren
		| R_paren
		| Vertical
		| Lexical_error of string
		| Eof;;

	let eof = Eof;;
	let invalid = None;;
	let compare = compare;;

	let make_pp ~(pattern: bool) ~(quali:bool) ~(paren:bool) (f: Format.formatter) (e: t): unit = (
		Format.pp_open_box f 2;
		let has_value = Obj.is_block (Obj.repr e) in
		if paren && has_value then (
			Format.pp_print_char f '(';
			Format.pp_print_cut f ()
		);
		if quali then (
			Format.pp_print_string f Modules.element_module;
			Format.pp_print_char f '.'
		);
		let hex = "0123456789abcdef" in
		begin match e with
		| R r ->
			Format.pp_print_string f "R";
			Format.pp_print_space f ();
			if quali then (
				Format.pp_print_string f Modules.reserved_module;
				Format.pp_print_char f '.'
			);
			Format.pp_print_string f (string_of_rw r)
		| A r ->
			Format.pp_print_string f "A";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				begin match r with
				| Attribute.Unknown s ->
					Format.pp_print_char f '(';
					if quali then (
						Format.pp_print_string f Modules.attribute_module;
						Format.pp_print_char f '.'
					);
					Format.pp_print_string f "Unknown";
					Format.pp_print_space f ();
					Format.pp_print_char f '\"';
					Format.pp_print_string f s;
					Format.pp_print_char f '\"';
					Format.pp_print_char f ')'
				| _ ->
					if quali then (
						Format.pp_print_string f Modules.attribute_module;
						Format.pp_print_char f '.'
					);
					Format.pp_print_string f (string_of_attr r)
				end
			)
		| P r ->
			Format.pp_print_string f "P";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				begin match r with
				| Pragma.Unknown s ->
					Format.pp_print_char f '(';
					if quali then (
						Format.pp_print_string f Modules.pragma_module;
						Format.pp_print_char f '.'
					);
					Format.pp_print_string f "Unknown";
					Format.pp_print_space f ();
					Format.pp_print_char f '\"';
					Format.pp_print_string f s;
					Format.pp_print_char f '\"';
					Format.pp_print_char f ')'
				| _ ->
					if quali then (
						Format.pp_print_string f Modules.pragma_module;
						Format.pp_print_char f '.'
					);
					Format.pp_print_string f (string_of_pragma r)
				end
			)
		| I (uid, sid) ->
			Format.pp_print_string f "I";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				Format.pp_print_string f "(\"";
				Format.pp_print_string f uid;
				Format.pp_print_string f "\", \"";
				Format.pp_print_string f sid;
				Format.pp_print_string f "\")"
			)
		| Integer_literal v ->
			Format.pp_print_string f "Integer_literal";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				Integer.pp f ~paren ~quali v
			)
		| Real_literal v ->
			Format.pp_print_string f "Real_literal";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				Real.pp f ~paren ~quali v
			)
		| Character_literal v ->
			Format.pp_print_string f "Character_literal";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				Format.pp_print_char f '\"';
				Format.pp_print_string f (String.escaped v);
				Format.pp_print_char f '\"'
			)
		| Character_code (bitwidth, code) ->
			Format.pp_print_string f "Character_code";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				Format.pp_print_char f '(';
				Format.pp_open_box f 0;
				Format.pp_print_int f bitwidth;
				Format.pp_print_char f ',';
				Format.pp_print_space f ();
				Format.pp_print_string f "0x";
				for i = bitwidth / 4 - 1 downto 0 do
					Format.pp_print_char f hex.[Int32.to_int (Int32.logand (Int32.shift_right_logical code (i * 4)) 15l)]
				done;
				Format.pp_print_char f 'l';
				Format.pp_close_box f ();
				Format.pp_print_char f ')'
			)
		| String_literal v ->
			Format.pp_print_string f "String_literal";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				Format.pp_print_char f '\"';
				Format.pp_print_string f (String.escaped v);
				Format.pp_print_char f '\"'
			)
		| Invalid_literal ->
			Format.pp_print_string f "Invalid_literal"
		| LT ->
			Format.pp_print_string f "LT"
		| LE ->
			Format.pp_print_string f "LE"
		| GT ->
			Format.pp_print_string f "GT"
		| GE ->
			Format.pp_print_string f "GE"
		| EQ ->
			Format.pp_print_string f "EQ"
		| NE ->
			Format.pp_print_string f "NE"
		| L_label ->
			Format.pp_print_string f "L_label"
		| R_label ->
			Format.pp_print_string f "R_label"
		| Box ->
			Format.pp_print_string f "Box"
		| Arrow ->
			Format.pp_print_string f "Arrow"
		| Slash ->
			Format.pp_print_string f "Slash"
		| Semicolon ->
			Format.pp_print_string f "Semicolon"
		| Colon ->
			Format.pp_print_string f "Colon"
		| Assign ->
			Format.pp_print_string f "Assign"
		| Asterisk ->
			Format.pp_print_string f "Asterisk"
		| Exponentiate ->
			Format.pp_print_string f "Exponentiate"
		| Comma ->
			Format.pp_print_string f "Comma"
		| Period ->
			Format.pp_print_string f "Period"
		| D_dot ->
			Format.pp_print_string f "D_dot"
		| Ampersand ->
			Format.pp_print_string f "Ampersand"
		| Plus ->
			Format.pp_print_string f "Plus"
		| Minus ->
			Format.pp_print_string f "Minus"
		| Quote ->
			Format.pp_print_string f "Quote"
		| L_paren ->
			Format.pp_print_string f "L_paren"
		| R_paren ->
			Format.pp_print_string f "R_paren"
		| Vertical ->
			Format.pp_print_string f "Vertical"
		| Lexical_error message ->
			Format.pp_print_string f "Lexical_error";
			Format.pp_print_space f ();
			if pattern then (
				Format.pp_print_char f '_'
			) else (
				Format.pp_print_char f '\"';
				Format.pp_print_string f (String.escaped message);
				Format.pp_print_char f '\"'
			)
		| Eof ->
			Format.pp_print_string f "Eof"
		end;
		if paren && has_value then (
			Format.pp_print_cut f ();
			Format.pp_print_char f ')'
		);
		Format.pp_close_box f ()
	);;

	let pp_pattern = make_pp ~pattern:true;;

	let pp = make_pp ~pattern:false;;

	let pp_typename ~(quali:bool) ~(paren:bool) (f: Format.formatter) (_: t list): unit = (
		if quali then (
			Format.pp_print_string f Modules.element_module;
			Format.pp_print_char f '.'
		);
		Format.pp_print_string f "t"
	);;

end;;
